package com.paradogs.framework.core.netty;

import com.paradogs.framework.core.events.ServerClientActiveEvent;
import com.paradogs.framework.core.events.ServerClientInactiveEvent;
import com.paradogs.framework.core.exceptions.GlobalExceptionDispatch;
import com.paradogs.framework.core.msg.ByteData;
import com.paradogs.framework.core.msg.PRMsgContextHolder;
import com.paradogs.framework.core.utils.EventUtils;
import com.paradogs.framework.core.utils.SpringUtils;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * @author: yumi
 * @date: 2023/7/27  9:32
 * @Description: 消息加入到 MAIN 处理队列
 */
@Slf4j
public abstract class PRAbMsgHandler<T> extends SimpleChannelInboundHandler<T> {

    /**
     * 消息处理
     */
    protected abstract void processMsg(ByteData msg) throws Exception;

    /**
     * 设置自定义参数
     */
    protected void setProps(ChannelHandlerContext ctx, ByteData msg) {}

    /**
     * 设置消息上下文
     * @param ctx
     * @param msg
     */
    protected void setContext(ChannelHandlerContext ctx, ByteData msg) {
        PRMsgContextHolder.setContext(ctx, msg.getMsgHeader().getPId(), msg.getMsgHeader());
        msg.setContext(PRMsgContextHolder.getSnapshot()); // 队列线程和 netty 线程不一样，要保存转移设置
    }

    /**
     * 消息处理
     * @param ctx
     * @param msg
     */
    protected final void channelRead0(ChannelHandlerContext ctx, ByteData msg) {

        setProps(ctx, msg);

        setContext(ctx, msg);

        log.debug("{} <<<<< [{}], {}", msg.getMsgHeader().getRoute(), msg.getMsgHeader().getSendServer(), msg);

        try {
            // 消息处理
            processMsg(msg);

        } catch (Exception e) {
            // 全局异常处理
            SpringUtils.getBean(GlobalExceptionDispatch.class).forward(e);

        }
    }

    /**
     * 连接建立事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        EventUtils.publishEvent(new ServerClientActiveEvent(ctx));
    }

    /**
     * 连接断开事件
     * @param ctx
     * @throws Exception
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        EventUtils.publishEvent(new ServerClientInactiveEvent(ctx));
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("{}", cause.getMessage(), cause);
    }
}
